<?php

namespace Home\Service;

use Home\Common\DemoConst;

/**
 * 收银系统 Service
 *
 * @author 李静波
 */
class PosService extends PSIBaseService {

	/**
	 * 生成新的POS单号
	 */
	private function genNewBillRef($db) {
		if ($db == null) {
			$db = M();
		}
		// $bs = new BizConfigService();
		// $pre = $bs->getSOBillRefPre();
		$pre = "POS";
		
		$mid = date("Ymd");
		
		$sql = "select ref from t_pos_bill where ref like '%s' order by ref desc limit 1";
		$data = $db->query($sql, $pre . $mid . "%");
		$sufLength = 4; // 末尾四位流水号
		$suf = str_pad("1", $sufLength, "0", STR_PAD_LEFT);
		if ($data) {
			$ref = $data[0]["ref"];
			$nextNumber = intval(substr($ref, strlen($pre . $mid))) + 1;
			$suf = str_pad($nextNumber, $sufLength, "0", STR_PAD_LEFT);
		}
		
		return $pre . $mid . $suf;
	}

	public function shopInfo() {
		if ($this->isNotOnline()) {
			return $this->emptyResult();
		}
		
		$result = array();
		$us = new UserService();
		$userId = $us->getLoginUserId();
		
		$db = M();
		
		if ($userId == DemoConst::ADMIN_USER_ID) {
			// 超级管理员，返回所有的店铺
			$sql = "select id, name from t_shop
					where use_pos = 1
					order by code";
			$data = $db->query($sql);
			foreach ( $data as $v ) {
				$item = array(
						"id" => $v["id"],
						"name" => $v["name"]
				);
				$result[] = $item;
			}
			
			return $result;
		}
		
		// 普通用户
		$sql = "select s.id, s.name 
				from t_shop s, t_shop_user u
				where s.use_pos = 1 and s.id = u.shop_id
					and (u.user_id = '%s' or s.shop_master_id = '%s')
				order by s.code";
		$data = $db->query($sql, $userId, $userId);
		foreach ( $data as $v ) {
			$item = array(
					"id" => $v["id"],
					"name" => $v["name"]
			);
			$result[] = $item;
		}
		
		return $result;
	}

	public function goodsByBarcode($params) {
		if ($this->isNotOnline()) {
			return $this->emptyResult();
		}
		
		$barcode = $params["barcode"];
		
		$result = array();
		
		$db = M();
		
		$sql = "select g.id, g.code, g.name, g.spec, u.name as unit_name,
					g.sale_price
				from t_goods_barcode c, t_barcode b, t_goods g, t_goods_unit u
				where b.id = c.barcode_id and c.goods_id = g.id
					and g.unit_id = u.id
					and b.barcode = '%s' 
				order by g.code ";
		$data = $db->query($sql, $barcode);
		foreach ( $data as $v ) {
			$item = array(
					"goodsId" => $v["id"],
					"goodsCode" => $v["code"],
					"goodsName" => $v["name"],
					"goodsSpec" => $v["spec"],
					"unitName" => $v["unit_name"],
					"goodsPrice" => $v["sale_price"]
			);
			
			$result[] = $item;
		}
		
		return $result;
	}

	public function commitBill($params) {
		if ($this->isNotOnline()) {
			return $this->notOnlineError();
		}
		
		$json = $params["jsonStr"];
		
		$bill = json_decode(html_entity_decode($json), true);
		if ($bill == null) {
			return $this->bad("传入的参数错误，不是正确的JSON格式");
		}
		
		$id = $bill["id"];
		$shopId = $bill["shopId"];
		$customerId = $bill["customerId"];
		$saleMoney = $bill["saleMoney"];
		$totalPay = $bill["totalPay"];
		$returnMoney = $bill["returnMoney"];
		
		$commit = $bill["commit"];
		
		$items = $bill["items"];
		
		$db = M();
		$db->startTrans();
		
		// 检查shopId
		$sql = "select name, warehouse_id from t_shop where id = '%s' ";
		$data = $db->query($sql, $shopId);
		if (! $data) {
			$db->rollback();
			return $this->bad("没有选择店铺");
		}
		$shopName = $data[0]["name"];
		$warehouseId = $data[0]["warehouse_id"];
		// 检查warehouseId
		$sql = "select name, inited from t_warehouse where id = '%s' ";
		$data = $db->query($sql, $warehouseId);
		if (! $data) {
			$db->rollback();
			return $this->bad("店铺[{$shopName}]没有设置出库仓库");
		}
		$warehouseName = $data[0]["name"];
		$inited = $data[0]["inited"];
		if ($inited == 0) {
			$db->rollback();
			return $this->bad("出库仓库[{$warehouseName}]还没有完成建账，不能有业务操作");
		}
		
		if ($customerId) {
			// 检查customerId
			$sql = "select name from t_customer where id = '%s' ";
			$data = $db->query($sql, $customerId);
			if (! $data) {
				$db->rollback();
				return $this->bad("选择的客户不存在");
			}
		} else {
			$customerId = "";
		}
		
		$idGen = new IdGenService();
		$us = new UserService();
		$userId = $us->getLoginUserId();
		$dataOrg = $us->getLoginUserDataOrg();
		$companyId = $us->getCompanyId();
		
		$bizDT = date("Y-m-d");
		
		if ($id) {
			// 之前保存过的单据
		} else {
			// 新单
			$id = $idGen->newId($db);
			
			$ref = $this->genNewBillRef($db);
			
			$sql = "insert into t_pos_bill (id, bill_status, bizdt, biz_user_id, customer_id, date_created,
						input_user_id, ref, warehouse_id, receiving_type, data_org, company_id, shop_id,
						sale_money, total_pay, return_money)
					values ('%s', 0, '%s', '%s', '%s', now(), 
						'%s', '%s', '%s', 1, '%s', '%s', '%s', 
						%f, %f, %f)";
			$rc = $db->execute($sql, $id, $bizDT, $userId, $customerId, $userId, $ref, $warehouseId, 
					$dataOrg, $companyId, $shopId, $saleMoney, $totalPay, $returnMoney);
			if ($rc === false) {
				$db->rollback();
				return $this->sqlError(__LINE__);
			}
		}
		
		// 明细记录
		foreach ( $items as $i => $v ) {
			$detailId = $idGen->newId($db);
			$goodsId = $v["goodsId"];
			if (! $goodsId) {
				continue;
			}
			
			// 检查goodsId
			$sql = "select code from t_goods where id = '%s' ";
			$d = $db->query($sql, $goodsId);
			if (! $d) {
				$db->rollback();
				return $this->bad("商品不存在");
			}
			
			$goodsCount = $v["goodsCount"];
			$goodsPrice = $v["goodsPrice"];
			$goodsMoney = $goodsPrice * $goodsCount;
			
			$sql = "insert into t_pos_bill_detail (id, date_created, goods_id, goods_count, goods_price,
						goods_money, show_order, posbill_id, data_org, company_id)
					values ('%s', now(), '%s', %d, %f, %f, %d, '%s', '%s', '%s')";
			$rc = $db->execute($sql, $detailId, $goodsId, $goodsCount, $goodsPrice, $goodsMoney, $i, 
					$id, $dataOrg, $companyId);
			if ($rc === false) {
				$db->rollback();
				return $this->sqlError(__LINE__);
			}
		}
		
		if (! $commit) {
			// 只是暂存数据
			$db->commit();
			
			return $this->ok($id);
		}
		
		// 出库，同步库存
		$sql = "select goods_id, goods_count, id
				from t_pos_bill_detail
				where posbill_id = '%s'
				order by show_order";
		$data = $db->query($sql, $id);
		foreach ( $data as $v ) {
			$pobBillDetailId = $v["id"];
			$goodsId = $v["goods_id"];
			$goodsCount = $v["goods_count"];
			
			// 出库的算法：
			// 因为POS单中只有商品id，并没有保质期，所以就从库存中按生产日期先进先出
			$sql = "select out_count, out_money, balance_count, balance_price, balance_money,
						begin_dt, expiration, end_dt
					from t_inventory_lot
					where warehouse_id = '%s' and goods_id = '%s'
						and balance_count > 0
					order by begin_dt";
			$data = $db->query($sql, $warehouseId, $goodsId);
			if (! $data) {
				// 没有商品库存记录，就不同步库存
				// TODO 这个地方如何处理，还有待商榷
				continue;
			}
			
			$invPrice = $data[0]["balance_price"];
			$invMoney = $invPrice * $goodsCount;
			$sql = "update t_pos_bill_detail
					set inventory_price = %f, inventory_money = %f
					where id = '%s' ";
			$rc = $db->execute($sql, $invPrice, $invMoney, $pobBillDetailId);
			if ($rc === false) {
				$db->rollback();
				return $this->sqlError(__LINE__);
			}
			
			// 允许出现负库存
			// 有多种商品，如果出现负库存，就让最后一条记录出现负库存
			$invCount = count($data);
			$outCount = $goodsCount;
			foreach ( $data as $invIndex => $invItem ) {
				if ($outCount == 0) {
					break;
				}
				
				$balanceCount = $invItem["balance_count"];
				$balancePrice = $invItem["balance_price"];
				$balanceMoney = $invItem["balance_money"];
				$totalCount = $invItem["out_count"];
				$totalMoney = $invItem["out_money"];
				
				$qcBeginDT = $this->toYmdForQC($invItem["begin_dt"]);
				if ($qcBeginDT == null) {
					$qcBeginDT = "1970-01-01";
				}
				$expiration = $invItem["expiration"];
				$qcEndDT = $this->toYmdForQC($invItem["end_dt"]);
				if ($qcEndDT == null) {
					$qcEndDT = "1970-01-01";
				}
				
				$c = 0;
				$p = 0;
				$m = 0;
				if ($outCount > $balanceCount) {
					$p = $balancePrice;
					if ($invIndex == $invCount - 1) {
						// 最后一条库存记录，允许出现负库存
						$c = $outCount;
						$m = $c * $p;
						$outCount = 0;
						
						$balanceCount -= $outCount;
						$balanceMoney -= $m;
					} else {
						// 当前库存全部出库，然后处理下一条库存记录
						$c = $balanceCount;
						$m = $c * $p;
						$outCount -= $balanceCount;
						
						$balanceMoney = 0;
						$balanceCount = 0;
					}
				} else {
					$c = $outCount;
					if ($outCount == $balanceCount) {
						$m = $balanceMoney;
						$p = $m / $c;
						
						$balanceMoney = 0;
						$balanceCount = 0;
					} else {
						$p = $balancePrice;
						$m = $c * $p;
						
						$balanceMoney -= $m;
						$balanceCount -= $outCount;
					}
					
					$outCount = 0;
				}
				
				// 库存明细账
				$sql = "insert into t_inventory_detail_lot(warehouse_id, goods_id, begin_dt, expiration,
							end_dt, out_count, out_price, out_money, balance_count, balance_price, 
							balance_money, ref_number, ref_type, data_org, company_id,
							biz_date, biz_user_id, date_created)
						values ('%s', '%s', '%s', %d,
							'%s', %d, %f, %f, %d, %f,
							%f, '%s', 'POS销售出库', '%s', '%s',
							'%s', '%s', now())";
				$rc = $db->execute($sql, $warehouseId, $goodsId, $qcBeginDT, $expiration, $qcEndDT, 
						$c, $p, $m, $balanceCount, $balancePrice, $balanceMoney, $ref, $dataOrg, 
						$companyId, $bizDT, $userId);
				if ($rc === false) {
					$db->rollback();
					return $this->sqlError(__LINE__);
				}
				
				// 库存总账
				$sql = "update t_inventory_lot
						set out_count = %d, out_price = %f, out_money = %f,
							balance_count = %d, balance_price = %f, balance_money = %f
						where warehouse_id = '%s' and goods_id = '%s'
							and begin_dt = '%s' and expiration = %d ";
				$totalCount += $c;
				$totalMoney += $m;
				$totalPrice = $m / $c;
				$rc = $db->execute($sql, $totalCount, $totalPrice, $totalMoney, $balanceCount, 
						$balancePrice, $balanceMoney, $warehouseId, $goodsId, $qcBeginDT, 
						$expiration);
				if ($rc === false) {
					$db->rollback();
					return $this->sqlError(__LINE__);
				}
			}
		}
		
		// 计算本单利润
		$sql = "select sum(inventory_money) as sum_inventory_money
				from t_pos_bill_detail
				where posbill_id = '%s' ";
		$data = $db->query($sql, $id);
		$sumInvMoney = $data[0]["sum_inventory_money"];
		if (! $sumInvMoney) {
			$sumInvMoney = 0;
		}
		$profit = $saleMoney - $sumInvMoney;
		
		$sql = "update t_pos_bill
				set inventory_money = %f, profit = %f
				where id = '%s' ";
		$rc = $db->execute($sql, $sumInvMoney, $profit, $id);
		if ($rc === false) {
			$db->rollback();
			return $this->sqlError(__LINE__);
		}
		
		// 修改单据本身的状态
		$sql = "update t_pos_bill
				set bill_status = 1000
				where id = '%s' ";
		$rc = $db->execute($sql, $id);
		if ($rc === false) {
			$db->rollback();
			return $this->sqlError(__LINE__);
		}
		
		$db->commit();
		
		return $this->ok($id);
	}

	public function getPrintBillData($id) {
		if ($this->isNotOnline()) {
			return $this->emptyResult();
		}
		
		$result = array();
		
		$db = M();
		
		$sql = "select ref, bizdt, customer_id, biz_user_id,
					shop_id, sale_money, total_pay, return_money,
					warehouse_id
				from t_pos_bill
				where id = '%s' ";
		$data = $db->query($sql, $id);
		if (! $data) {
			return $result;
		}
		
		$v = $data[0];
		$result["ref"] = $v["ref"];
		$result["bizDT"] = $this->toYMD($v["bizdt"]);
		$result["saleMoney"] = $v["sale_money"];
		$result["totalPay"] = $v["total_pay"];
		$result["returnMoney"] = $v["return_money"];
		
		$customerId = $v["customer_id"];
		$bizUserId = $v["biz_user_id"];
		$shopId = $v["shop_id"];
		$warehouseId = $v["warehouse_id"];
		
		$result["customerName"] = "N/A";
		if ($customerId) {
			$sql = "select name from t_customer where id = '%s' ";
			$data = $db->query($sql, $customerId);
			if ($data) {
				$result["customerName"] = $data[0]["name"];
			}
		}
		
		$sql = "select name from t_shop where id = '%s' ";
		$data = $db->query($sql, $shopId);
		if ($data) {
			$result["shopName"] = $data[0]["name"];
		}
		
		$sql = "select name from t_user where id = '%s' ";
		$data = $db->query($sql, $bizUserId);
		if ($data) {
			$result["bizUserName"] = $data[0]["name"];
		}
		
		$sql = "select name from t_warehouse where id = '%s' ";
		$data = $db->query($sql, $warehouseId);
		if ($data) {
			$result["warehouseName"] = $data[0]["name"];
		}
		
		// 商品明细
		$items = array();
		
		$sql = "select g.name, g.spec, p.goods_count, p.goods_price, p.goods_money,
					u.name as unit_name
				from t_pos_bill_detail p, t_goods g, t_goods_unit u
				where p.goods_id = g.id and g.unit_id = u.id
					and p.posbill_id = '%s'
				order by p.show_order";
		$data = $db->query($sql, $id);
		
		$totalCount = 0;
		foreach ( $data as $v ) {
			$item = array(
					"goodsName" => $v["name"] . " " . $v["spec"],
					"goodsCount" => $v["goods_count"],
					"goodsPrice" => $v["goods_price"],
					"goodsMoney" => $v["goods_money"],
					"unitName" => $v["unit_name"]
			);
			
			$totalCount += $v["goods_count"];
			
			$items[] = $item;
		}
		
		$result["totalCount"] = $totalCount;
		
		$result["items"] = $items;
		
		$result["printDT"] = date("Y-m-d H:i:s");
		
		return $result;
	}
}